from machine import Pin
from neopixel import NeoPixel
from font_map import *
import time

class MugenRGB():
    FONT7 = 0
    FONT5 = 1
    
    def __init__(self, pin, pattern):
        pin = Pin(pin, Pin.OUT)
        self.width = len(pattern[0]) * 8
        self.height = len(pattern) * 8
        self.pattern = pattern
        self.n = self.width * self.height
        self.np = NeoPixel(pin, self.n)
        self.buffer = []
        self.font_list = (Font7(), Font5())
        for y in range(self.height):
            line = []
            for x in range(self.width):
                line.append([0,0,0])
            self.buffer.append(line)
        
    
    def clear(self):
        self.fill([0,0,0])

    def fill(self, color):
        color = self.color_handler(color)
        for y in range(self.height):
            for x in range(self.width):
                self.buffer[y][x] = color

    def draw_point(self, x, y, color):
        color = self.color_handler(color)
        if x < self.width and y < self.height:
            self.buffer[y][x] = color

    def draw_rect(self, x1, y1, x2, y2, color, fill=False):
        color = self.color_handler(color)
        # Top & Bottom line
        for x in range(x1, x2+1):
            if x > self.width or y1 > self.height:
                continue
            self.buffer[y1][x] = color
            if y2 > self.height:
                continue
            self.buffer[y2][x] = color
        # Left & Right line
        for y in range(y1+1, y2):
            if y > self.width or x1 > self.height:
                continue
            self.buffer[y][x1] = color
            if x2 > self.height:
                continue
            self.buffer[y][x2] = color
        # If Fill? draw fill
        if fill:
            for y in range(y1+1, y2):
                for x in range(x1+1, x2):
                    if x > self.width or y > self.height:
                        continue
                    self.buffer[y][x] = color

    # y = ax + b
    def draw_line(self, x1, y1, x2, y2, color):
        delta_x = abs(x2 - x1)
        delta_y = abs(y2 - y1)
        a = delta_y / delta_x
        b = y1 - a * x1
        for x in range(x1, x2+1):
            y = round(a * x + b)
            if x > self.width or y > self.height:
                continue
            self.buffer[y][x] = color

    def draw_bit_map(self, x, y, bit_map, color):
        for y1, row in enumerate(bit_map):
            for x1, pixel in enumerate(row):
                if pixel == "1":
                    x_tmp = max(min(x+x1, self.width), 0)
                    y_tmp = max(min(y+y1, self.height), 0)
                    self.draw_point(x_tmp, y_tmp, color)
        

    def draw_text(self, x, y, text, font, color):
        bit_map = self.string_to_string_bits(text, font)
        self.draw_bit_map(x, y, bit_map, color)
                
    def scroll_text(self, y, text, font, color, delay=500):
        bit_map = self.string_to_string_bits(text, font)
        for i in range(len(bit_map[0]) - self.width):
            self.draw_bit_map(-i, y, bit_map, color)
            self.write()
            time.sleep_ms(delay)
            self.clear()

    def write(self):
        temp = list(self.buffer)
        for y in range(self.height):
            for x in range(self.width):
                pattern_x = x // 8
                pattern_y = y // 8
                pattern_i = self.pattern[pattern_y][pattern_x] - 1
                #print("pattern: x: %s, y: %s, i: %s"%(pattern_x, pattern_y, pattern_i))
                module_x = x % 8
                module_y = y % 8
                module_i = module_y * 8 + module_x
                #print("module: x: %s, y: %s, i: %s"%(module_x, module_y, module_i))
                index = module_i + pattern_i * 64
                #print("index: %s, x: %s, y: %s"%(index, x, y))
                self.np[index] = self.buffer[y][x]
        #print(np)
        self.np.write()
    
    def color_handler(self, color):
        if isinstance(color, list) and len(color) == 3:
            return color
        elif isinstance(color, int):
            r = color >> 16 & 0xFF
            g = color >> 8 & 0xFF
            b = color >> 0 & 0xFF
            return [r, g, b]
        else:
            raise ValueError("Color must be 24-bit  RGB hex or list of 3 8-bit RGB")

    def string_to_string_bits(self, s, font):
        smap = []
        for i in range(self.font_list[font].HEIGHT):
            bits = ''
            for letter in s:
                letter = self.font_list[font].get(letter)
                try:
                    bits += letter[-i -1]
                except:
                    for j in range(len(letter[0])):
                        bits += '0'
                bits += '0'
            smap.append(bits)
        smap.reverse()
        return smap


